/*
 * This file or a portion of this file is licensed under the terms of
 * the Globus Toolkit Public License, found in file ../GTPL, or at
 * http://www.globus.org/toolkit/download/license.html. This notice must
 * appear in redistributions of this file, with or without modification.
 *
 * Redistributions of this Software, with or without modification, must
 * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
 * some other similar material which is provided with the Software (if
 * any).
 *
 * Copyright 1999-2004 University of Chicago and The University of
 * Southern California. All rights reserved.
 */
package org.griphyn.vdl.util;

import java.util.HashMap;

/**
 * This class maps back and forth between a short identifier, and
 * some unique, abstract identifier that is generated by a sequence.
 * Instantiated with the default constructor, the generated
 * identifiers will satisfy NMTOKEN.
 *
 * @author Jens-S. Vöckler
 * @author Yong Zhao
 * @version $Revision: 50 $
 */
public class SequenceMapping
{
  /**
   * The forward mapping between the external indentifier and
   * the internally generated sequence for the identifier.
   */
  private HashMap m_forward;

  /**
   * The reverse mapping between the sequence-generated identifier,
   * and the external identifier. The reverse mapping is also
   * employed to rule out duplicates.
   */
  private HashMap m_backward;

  /**
   * The sequence counter employed by this generator. Please note
   * that multiple instances of this class will produce the same
   * sequences!
   */
  private SequenceGenerator m_sequence;

  /**
   * A prefix string, initialized to "ID" for the default c'tor.
   */
  private String m_prefix;

  /**
   * C'tor: This will generate an instance that generated IDxxxxx
   * symbols. Please note that multiple instances of this class will
   * produce the same sequences!
   */
  public SequenceMapping()
  {
    this.m_prefix = "ID";
    this.m_forward = new HashMap();
    this.m_backward = new HashMap();
    this.m_sequence = new SequenceGenerator();
  }

  /**
   * C'tor: Instances from this contructor will generate ${prefix}xxxxx.
   * Please note that multiple instances of this class with the same
   * prefix will produce the same sequences!
   *
   * @param prefix is a prefix to the generated sequence. 
   */
  public SequenceMapping( String prefix )
  {
    this.m_prefix = new String(prefix);
    this.m_forward = new HashMap();
    this.m_backward = new HashMap();
    this.m_sequence = new SequenceGenerator();
  }

  /**
   * Creates and caches a unique id for a given short identifier.
   * @param id is the external identifier which needs to be forward mapped.
   * @return a sequence-generated identifier to use instead.
   */
  public String forward( String id )
  {
    String result = (String) this.m_forward.get(id);
    if ( result == null ) {
      // need to create a new entry
      do {
	result = this.m_prefix + this.m_sequence.generate();
      } while ( this.m_backward.containsKey(result) );
      this.m_forward.put( id, result );
      this.m_backward.put( result, id );
    }

    Logging.instance().log( "map", 5, id + " <=> " + result );
    return result;
  }

  /**
   * Obtains existing mapping without producing a new one. May return
   * <code>null</code> if no mapping exists.
   *
   * @param shortid is the external identifier to check fwd mapping for
   * @return null, if no such mapping exists.
   */
  public String get( String shortid )
  {
    return (String) this.m_forward.get(shortid);
  }
}
